package reports

import (
	"database/sql"
	"fmt"
	"sort"
	"strconv"
	"time"

	"github.com/go-redis/redis/v8"
	"shqsoft.cn/pas3ui/base"
)

func readFromRedis(repConf *Config, tName string, unit int) (datas []map[string]string, total int, err error) {
	prev := tName[0:4]
	if prev == "LCFX" {
		var hasAcbl, hasAvg, hasSum bool
		for _, col := range repConf.Columns {
			if col.GroupCalc == "acbl" {
				hasAcbl = true
			} else if col.GroupCalc == "avg" {
				hasAvg = true
			} else if col.GroupCalc == "sum" {
				hasSum = true
			}
		}
		var acblDatas, avvlDatas map[string]string
		if hasAcbl {
			hkey1 := fmt.Sprintf("clbh:%s", tName)
			acblDatas, err = base.RedisCli.HGetAll(ctx, hkey1).Result()
			if err != nil {
				return
			}
		}
		if hasAvg || hasSum {
			hkey2 := fmt.Sprintf("clah:%s", tName)
			avvlDatas, err = base.RedisCli.HGetAll(ctx, hkey2).Result()
			if err != nil {
				return
			}
		}
		datas = make([]map[string]string, 0, 12)
		var feMap map[string]string
		if len(acblDatas) > 0 {
			feMap = acblDatas
		} else {
			feMap = avvlDatas
		}
		keys := make([]string, 0, len(feMap))
		for k := range feMap {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		if unit == 0 {
			unit = repConf.Unit
		}
		if unit == 0 {
			unit = 1
		}
		for _, k := range keys {
			data := make(map[string]string, 3)
			data["TIME"] = k
			if hasAcbl {
				val, _ := strconv.ParseFloat(acblDatas[k], 64)
				data["ACBL"] = fmt.Sprintf("%.2f", val/float64(unit))
			}
			if hasAvg {
				val, _ := strconv.ParseFloat(avvlDatas[k], 64)
				data["AVVL"] = fmt.Sprintf("%.2f", val/float64(unit))
			} else if hasSum {
				val, _ := strconv.ParseFloat(avvlDatas[k], 64)
				data["JE"] = fmt.Sprintf("%.2f", val/float64(unit))
			}
			datas = append(datas, data)
		}
	} else if prev == "PIE_" {
		hkey := fmt.Sprintf("pie:%s", tName)
		var pieDatas []redis.Z
		pieDatas, err = base.RedisCli.ZRevRangeWithScores(ctx, hkey, 0, -1).Result()
		if err != nil {
			return
		}
		datas = make([]map[string]string, 0, 12)
		unit := 1
		if repConf.Unit > 0 {
			unit = repConf.Unit
		}
		zvQt := 0.0
		for i, zv := range pieDatas {
			data := make(map[string]string, 2)
			if i > 10 {
				zvQt += zv.Score
				continue
			}
			data["TPNM"] = base.ToString(zv.Member)
			if zv.Score == 0 {
				continue
			}
			data["JE"] = fmt.Sprintf("%.2f", zv.Score/float64(unit))
			datas = append(datas, data)
		}
		if zvQt > 0 {
			data := make(map[string]string, 2)
			data["TPNM"] = "其它"
			data["JE"] = fmt.Sprintf("%.2f", zvQt/float64(unit))
			datas = append(datas, data)
		}
	} else {
		err = fmt.Errorf("临时表前缀为%s的redis取数逻辑还没有实现", prev)
	}
	total = len(datas)
	return
}

func writeToRedis(rows *sql.Rows, pipe redis.Pipeliner, hkey, timeLevel string) (err error) {
	defer rows.Close()
	var format string
	switch timeLevel {
	case "year":
		format = "2006"
	case "quarter":
		format = "2006"
	case "month":
		format = "200601"
	default:
		format = "20060102"
	}
	vals := make([]interface{}, 0, 24)
	for rows.Next() {
		var dtid time.Time
		var acbl float64
		err = rows.Scan(&dtid, &acbl)
		if err != nil {
			return err
		}
		timeStr := dtid.Format(format)
		if timeLevel == "quarter" {
			switch dtid.Month() {
			case 1, 2, 3:
				timeStr += "-1"
			case 4, 5, 6:
				timeStr += "-2"
			case 7, 8, 9:
				timeStr += "-3"
			default:
				timeStr += "-4"
			}
		}
		vals = append(vals, timeStr, acbl)
	}
	if len(vals) == 0 {
		return
	}
	err = pipe.HMSet(ctx, hkey, vals).Err()
	if err != nil {
		return err
	}
	err = pipe.Expire(ctx, hkey, time.Hour*8).Err()
	return
}

func writePieDataToRedis(rows *sql.Rows, pipe redis.Pipeliner, tName string) (err error) {
	hkey := fmt.Sprintf("pie:%s", tName)
	var name string
	var val float64
	defer rows.Close()
	for rows.Next() {
		err = rows.Scan(&name, &val)
		if err != nil {
			return
		}
		err = pipe.ZIncrBy(ctx, hkey, val, name).Err()
		if err != nil {
			return
		}
		err = pipe.Expire(ctx, hkey, time.Hour*8).Err()
		if err != nil {
			return
		}
	}
	return
}

func writeTpnoPieDataToRedis(row *sql.Row, pipe redis.Pipeliner, tName string, itemNames []string) (err error) {
	ilen := len(itemNames)
	vals := make([]float64, ilen)
	pvals := make([]interface{}, ilen)
	for i := 0; i < ilen; i++ {
		pvals[i] = &vals[i]
	}
	err = row.Scan(pvals...)
	if err != nil {
		return
	}
	hkey := fmt.Sprintf("pie:%s", tName)
	for i, in := range itemNames {
		err = pipe.ZIncrBy(ctx, hkey, vals[i], in).Err()
		if err != nil {
			return
		}
		err = pipe.Expire(ctx, hkey, time.Hour*8).Err()
		if err != nil {
			return
		}
	}
	return
}
